package com.itclass.auth.authentication.filter;


import com.itclass.auth.authentication.adapter.AuthenticationAdapter;
import com.itclass.auth.authentication.adapter.RequestMatcherAdapter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AndRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private String usernameParameter = "username";

    private String passwordParameter = "password";
    private String loginTypeName = "loginType";

    private RequestMatcherAdapter requestMatcherAdapter = new RequestMatcherAdapter();

    private List<AuthenticationAdapter> authenticationAdapterList;
    protected LoginAuthenticationFilter() {
        super("/login");
    }


    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        return super.requiresAuthentication(request, response) || requestMatcherAdapter.matches(request);
    }

    private boolean postOnly = true;
    protected LoginAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    protected LoginAuthenticationFilter(RequestMatcher ... requestMatcher) {
        super(new AndRequestMatcher(requestMatcher));
    }

    protected LoginAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
        super(defaultFilterProcessesUrl, authenticationManager);
    }

    protected LoginAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher, AuthenticationManager authenticationManager) {
        super(requiresAuthenticationRequestMatcher, authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        String loginType = obtainLoginType(request);

        AuthenticationAdapter targetAuthenticationAdapter =null;
        for (AuthenticationAdapter authenticationAdapter : getAuthenticationAdapterList()) {
            if (authenticationAdapter.supports(loginType)) {
                targetAuthenticationAdapter = authenticationAdapter;
                break;
            }
        }

        if (null == targetAuthenticationAdapter) {
            throw new AuthenticationServiceException("Authentication loginType not supported: " + loginType);
        }

        Authentication authRequest = targetAuthenticationAdapter.handle(request);

        return this.getAuthenticationManager().authenticate(authRequest);
    }

    private String obtainLoginType(HttpServletRequest request) {
        return request.getParameter(loginTypeName);
    }

    public String getUsernameParameter() {
        return usernameParameter;
    }

    public void setUsernameParameter(String usernameParameter) {
        this.usernameParameter = usernameParameter;
    }

    public String getPasswordParameter() {
        return passwordParameter;
    }

    public void setPasswordParameter(String passwordParameter) {
        this.passwordParameter = passwordParameter;
    }

    public List<AuthenticationAdapter> getAuthenticationAdapterList() {
        return authenticationAdapterList;
    }

    public void setAuthenticationAdapterList(List<AuthenticationAdapter> authenticationAdapterList) {
        this.authenticationAdapterList = authenticationAdapterList;
    }

    public void setRequestMatcherAdapter(RequestMatcherAdapter requestMatcherAdapter) {
        this.requestMatcherAdapter = requestMatcherAdapter;
    }

    public RequestMatcherAdapter getRequestMatcherAdapter() {
        return this.requestMatcherAdapter;
    }

}
